package org.dftproject.genesis.ui.presentation.tabcontrol;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;

public class TabControl extends Composite {

	private final Canvas tabsCanvas;
	private TabControlFigure tabControlFigure;
	
	private final ArrayList<TabItem> items = new ArrayList<TabItem>();
	private final Map<TabItem, TabFigure> figureByTabItem = new HashMap<TabItem, TabFigure>();
	
	private final List<ITabControlListener> listeners = new LinkedList<ITabControlListener>(); 

	private TabItem selectedTabItem;
	
	public TabControl(Composite parent, int style) {
		super(parent, style);
		
		tabsCanvas = new Canvas(this, SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND);
		
		LightweightSystem lws = new LightweightSystem(tabsCanvas);
		lws.setContents(tabControlFigure = new TabControlFigure(this));
		
		addControlListener(new ControlListener() {

			public void controlMoved(ControlEvent e) {
			}

			public void controlResized(ControlEvent e) {
				Point size = getSize();
				Dimension tabsSize = tabControlFigure.getPreferredSize(size.x, -1);
				tabsCanvas.setBounds(0, 0, size.x, tabsSize.height);
			}
			
		});
		addPaintListener(new PaintListener() {

			public void paintControl(PaintEvent e) {
				Point size = getSize();
				Rectangle tabsBounds = tabsCanvas.getBounds();
				
				e.gc.setForeground(tabControlFigure.getBorderColor());
				e.gc.drawLine(0, tabsBounds.height, 0, size.y);
				e.gc.drawLine(size.x - 1, tabsBounds.height, size.x - 1, size.y);
				e.gc.drawLine(0, size.y - 1, size.x, size.y - 1);
			}
			
		});
	}
	
	@Override
	public void setMenu(Menu menu) {
		tabsCanvas.setMenu(menu);
	}

	protected void createTabItem(TabItem item) {
		if (items.size() == 1)
			items.get(0).setClosable(true);
		
		items.add(item);
		figureByTabItem.put(item, tabControlFigure.addTabItem(item));
		if (items.size() == 1)
			item.setClosable(false);
	}

	public TabItem[] getTabItems() {
		return items.toArray(new TabItem[0]);
	}

	public void setSelection(TabItem item) {
		if (item == selectedTabItem)
			return;
		
		TabFigure figure = getTabItemFigure(selectedTabItem);
		if (figure != null)
			figure.setSelected(false);
		
		figure = getTabItemFigure(item);
		if (figure != null)
			figure.setSelected(true);
		
		selectedTabItem = item;
		
		notifyTabItemSelected(item);
	}

	@Override
	public Rectangle getClientArea() {
		Point size = getSize();
		Rectangle tabsBounds = tabsCanvas.getBounds();
		Rectangle clientArea = new Rectangle(1, tabsBounds.height, size.x - 2, size.y - tabsBounds.height - 1);
		return clientArea;
	}

	protected TabFigure getTabItemFigure(TabItem item) {
		return figureByTabItem.get(item);
	}

	public void closeTabItem(TabItem item) {
		if (item == null)
			return;
		
		items.remove(item);
		tabControlFigure.remove(figureByTabItem.remove(item));
		if (selectedTabItem == item) {
			selectedTabItem = null;
			if (!items.isEmpty())
				setSelection(items.get(items.size() - 1));
		}
		
		notifyTabItemClosed(item);
		
		item.dispose();
		
		if (items.size() == 1)
			items.get(0).setClosable(false);
	}
	
	public void addTabControlListener(ITabControlListener listener) {
		listeners.add(listener);
	}
	
	public void removeTabControlListener(ITabControlListener listener) {
		listeners.remove(listener);
	}

	public void newTab() {
		for (ITabControlListener listener : listeners)
			listener.newTab();
	}
	
	protected void notifyTabItemSelected(TabItem item) {
		for (ITabControlListener listener : listeners)
			listener.tabSelected(item);
	}
	
	protected void notifyTabItemClosed(TabItem item) {
		for (ITabControlListener listener : listeners)
			listener.tabClosed(item);
	}

}
